package model;


import controller.Commandable;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import model.datareader.CSVReader;
import model.datareader.DataReader;
import model.datareader.DataReaderFactory;
import model.datareader.TabReader;


/**
 * @author Stephen Hunt, Niel Lebeck
 *         Receives input from a data file and manipulates it in
 *         ways needed by the view.
 */
public class WebHistoryModel {
    private List<WebsiteVisit> myHistory;

    /**
     * Basic constructor.
     * @param commandProcessor CommandProcessor in charge of this model.
     */
    public WebHistoryModel (Commandable<?, WebHistoryModel> commandProcessor) {
        commandProcessor.setModel(this);
    }

    /**
     * Creates a FileChecker which ensures proper data is loaded.
     * @throws WebHistoryDataException Thrown if supported file types not specified
     * @return Returns a FileChecker that accepts CSV and TXT files.
     */
    public FileChecker createFileChecker() throws WebHistoryDataException {
        List<String> fileTypeList = new ArrayList<String>();
        String supportedTypes = null;
        ResourceBundle myResources = ResourceBundle.getBundle("resources.WebHistory");
        try {
            supportedTypes = myResources.getString("filetypes");
        }
        catch (MissingResourceException e) {
            throw new WebHistoryDataException(
                    "supported filetypes not specified in properties file");
        }
        String[] supportedTypeArray = supportedTypes.split(",");
        for (String typeString : supportedTypeArray) {
            fileTypeList.add(typeString);
        }
        return new FileChecker(fileTypeList);
    }

    /**
     * Imports data file into model.
     * @param dataFile File to be loaded into the model.
     * @throws WebHistoryDataException Thrown if improper file is loaded
     */
    public void importData (File dataFile) throws WebHistoryDataException {
        FileChecker myChecker = createFileChecker();
        String fileType = myChecker.isSupported(dataFile);
        DataReader currentReader = DataReaderFactory.createDataReader(fileType);
        if (currentReader == null) {
            throw new WebHistoryDataException("data file not supported");
        }
        myHistory = currentReader.readData(dataFile);
    }

    /**
     * Clears all data stored in model.
     */
    public void clearData () {
        myHistory = null;
    }

    /**
     * @return websiteList list of string names of all websites visited by the
     *         user
     */
    public List<String> getAllWebsites () {
        List<String> websiteList = new ArrayList<String>();
        for (WebsiteVisit current: myHistory) {
            if (!websiteList.contains(current.getURL()) && current.isActive()) {
                websiteList.add(current.getURL());
            }
        }
        return websiteList;
    }

    /**
     * @param website URL of website to be checked
     * @return numVisits number of times the user has visited a
     *         given website.
     */
    public int getNumVisits (String website) {
        int numVisits = 0;
        for (WebsiteVisit current: myHistory) {
            if (current.getURL().equals(website) && current.isActive()) {
                numVisits++;
            }
        }
        return numVisits;
    }

    /**
     * @param website URL of website to be checked
     * @param timestamp Time visited website
     * @return name of website visited immediately after the given website at
     *         the given time.
     */
    public String getNextVisit (String website, Time timestamp) {
        for (WebsiteVisit current: myHistory) {
            if (current.getURL().equals(website)
                    && current.getTimestamp().equals(timestamp)
                    && current.isActive()
                    && !isLast(current)) {
                return getNextSite(current).getURL();
            }
        }
        return null;
    }

    private WebsiteVisit getNextSite (WebsiteVisit visit) {
        if (visit.isActive() && !isLast(visit)) {
            return myHistory.get(myHistory.indexOf(visit) + 1);
        }
        return null;
    }

    /**
     * @param website URL of website to be checked
     * @return nextVisits list of WebsiteVisits accessing a given website.
     */
    public List<String> getAllNextVisits (String website) {
        List<String> nextVisits = new ArrayList<String>();
        for (WebsiteVisit current: myHistory) {
            if (current.getURL().equals(website)
                    && current.isActive() && !isLast(current)) {
                nextVisits.add(getNextSite(current).getURL());
            }
        }
        return nextVisits;
    }

    /**
     * Returns number of times one website immediately follows another.
     *
     * @param currentWebsite URL of website user transitions from
     * @param nextWebsite URL of website user transitions to
     * @return numTrans number of transitions from currentWebsite to nextWebsite
     */
    public int getTransitionFreq (String currentWebsite, String nextWebsite) {
        int numTrans = 0;

        for (WebsiteVisit current: myHistory) {
            if (current.getURL().equals(currentWebsite) &&
                    getNextSite(current).getURL().equals(nextWebsite) &&
                    current.isActive()) {
                numTrans++;
            }
        }
        return numTrans;
    }

    /**
     * @param website URL of the website to be checked
     * @return timeSpent amount of time spent on website
     */
    public long timeSpentOnWebsite (String website) {
        long timeSpent = 0;
        for (WebsiteVisit current: myHistory) {
            if (current.getURL().equals(website) && current.isActive()) {
                timeSpent += current.getVisitDuration(getNextSite(current));
            }
        }
        return timeSpent;
    }

    /**
     * @param website URL of the website to be checked
     * @return visitTimes a list of times at which the given website was visited
     */
    public List<Time> getAllVisitTimes (String website) {
        List<Time> visitTimes = new ArrayList<Time>();
        for (WebsiteVisit current: myHistory) {
            if (current.getURL().equals(website) && current.isActive()) {
                visitTimes.add(current.getTimestamp());
            }
        }
        return visitTimes;
    }

    /**
     * Restricts access to given website by marking it inactive, so it doesn't
     * appear in some searches.
     *
     * @param website URL of the website to be restricted.
     */
    public void restrictWebsite (String website) {
        for (WebsiteVisit current: myHistory) {
            if (current.getURL().equals(website)) {
                current.setActive(false);
            }
        }
    }

    /**
     * Allows access to given website by marking it active, so if it was
     * inactive before it will now appear in some searches.
     *
     * @param website URL of the website to be allowed.
     */
    public void allowWebsite (String website) {
        for (WebsiteVisit current: myHistory) {
            if (current.getURL().equals(website)) {
                current.setActive(true);
            }
        }
    }

    /**
     * Clears any restrictions on any websites in the data set.
     */
    public void clearRestrictions () {
        for (WebsiteVisit current: myHistory) {
            current.setActive(true);
        }
    }

    /**
     * Checks if a WebsiteVisit is the last visit stored in myHistory.
     * @param current the WebsiteVisit to be checked.
     * @return true if current is the last visit stored in myHistory.
     */
    public boolean isLast(WebsiteVisit current) {
        return myHistory.indexOf(current) + 1 >= myHistory.size();
    }



}
